package cyou.breathe.blog.article.domain.service;


import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cyou.breathe.blog.api.article.request.*;
import cyou.breathe.blog.api.article.response.ArticleCreateResponse;
import cyou.breathe.blog.api.article.response.ArticleDeleteResponse;
import cyou.breathe.blog.api.article.response.ArticleUpdateResponse;
import cyou.breathe.blog.article.domain.entity.Article;
import cyou.breathe.blog.article.infrastructure.exception.ArticleErrorCode;
import cyou.breathe.blog.article.infrastructure.exception.ArticleException;
import cyou.breathe.blog.article.infrastructure.mapper.ArticleMapper;
import cyou.breathe.blog.lock.DistributeLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


/**
 * @author: breathe
 * @createTime: 2025-08-29
 */
@Service
@Slf4j
public class ArticleService extends ServiceImpl<ArticleMapper, Article> {

    @Autowired
    private ArticleMapper articleMapper;

    /**
     * 创建文章
     * @param articleCreateRequest
     * @return
     */
    @DistributeLock(keyExpression = "#articleCreateRequest.authorId", scene = "CREATE_ARTICLE")
    public ArticleCreateResponse createArticle(ArticleCreateRequest articleCreateRequest) {
        // 先分析一下怎么写, 在这里我们不可能让同一个接口连续调两次的, 所以我们需要做一个幂等
        // 比如他需要调用我的接口获取一个token, 然后通过这个token做一个校验, 但我认为在这个场景下, 太重了这样
        // 由于没有一个seo这样的东西, 导致我们的文章可能不唯一, 所以这里我们需要一个全局唯一标识符,
        // 考虑之后还是先用锁来实现吧, 之后再来做优化

        //先获取folder下的文章, 然后判断其中的文章是否已经存在, 如果存在直接返回true

        //幂等
        ArticleCreateResponse response = new ArticleCreateResponse();

        //查一下是否有重复
        LambdaQueryWrapper<Article> queryWrapper = Wrappers.lambdaQuery(Article.class)
                .eq(Article::getFolderId, articleCreateRequest.getFolderId())
                .eq(Article::getTitle, articleCreateRequest.getTitle())
                .eq(Article::getAuthorId, articleCreateRequest.getAuthorId());


        Article multiArticle = articleMapper.selectOne(queryWrapper);
        if (ObjectUtils.isNotEmpty(multiArticle)) {
            //重复, 直接幂等返回
            if (checkArticle(multiArticle, articleCreateRequest)) {
                response.setArticleId(multiArticle.getId());
                response.setSuccess(true);
                return response;
            }

            //在同一个目录下创建相同的文件
            if (multiArticle.getFolderId().equals(articleCreateRequest.getFolderId()) && multiArticle.getAuthorId().equals(articleCreateRequest.getAuthorId()) && multiArticle.getTitle().equals(articleCreateRequest.getTitle())) {
                response.setErrorCode(ArticleErrorCode.ARTICLE_CREATE_DUPLICATE);
                return response;
            }
        }

        Article article = new Article();
        article.createArticle(articleCreateRequest);
        if (!this.save(article)) {
            response.setErrorCode(ArticleErrorCode.ARTICLE_CREATE_FAILED);
            return response;
        }
        response.setArticleId(article.getId());
        response.setSuccess(true);
        return response;
    }

    /**
     * 检查文章是否重复
     * @param article
     * @param articleCreateRequest
     * @return
     */
    private boolean checkArticle(Article article, ArticleCreateRequest articleCreateRequest) {
        if (article.getTitle().equals(articleCreateRequest.getTitle())
        && article.getContent().equals(articleCreateRequest.getContent())
        && article.getState().equals(articleCreateRequest.getState())
        && article.getTags().equals(JSON.toJSONString(articleCreateRequest.getTags()))
        && article.getAuthorId().equals(articleCreateRequest.getAuthorId())
        && article.getFolderId().equals(articleCreateRequest.getFolderId())) {
            return true;
        }
        return false;
    }

    /**
     * 修改文章
     * @param articleUpdateRequest
     * @return
     */
    @DistributeLock(keyExpression = "#articleUpdateRequest.authorId", scene = "UPDATE_ARTICLE")
    public ArticleUpdateResponse updateArticle(ArticleUpdateRequest articleUpdateRequest) {
        ArticleUpdateResponse response = new ArticleUpdateResponse();

        Article article = articleMapper.selectById(articleUpdateRequest.getArticleId());

        Assert.notNull(article, () -> new ArticleException(ArticleErrorCode.ARTICLE_UPDATE_FAILED));

        article.updateArticle(articleUpdateRequest);
        if (!this.updateById(article)) {
            response.setSuccess(false);
            response.setErrorCode(ArticleErrorCode.ARTICLE_UPDATE_FAILED);

            return response;
        }

        response.setSuccess(true);
        response.setArticleId(article.getId());
        return response;
    }

    /**
     * 删除文章
     * @param articleDeleteRequest
     * @return
     */
    @DistributeLock(keyExpression = "articleDeleteRequest.authorId", scene = "DELETE_ARTICLE")
    public ArticleDeleteResponse deleteArticle(ArticleDeleteRequest articleDeleteRequest) {
        ArticleDeleteResponse response = new ArticleDeleteResponse();

        LambdaUpdateWrapper<Article> updateWrapper = Wrappers.lambdaUpdate(Article.class)
                .eq(Article::getAuthorId, articleDeleteRequest.getAuthorId())
                .eq(Article::getId, articleDeleteRequest.getArticleId());

        if (articleMapper.delete(updateWrapper) == 0) {
            response.setSuccess(false);
            response.setErrorCode(ArticleErrorCode.ARTICLE_NOT_EXIST);

            return response;
        }

        response.setSuccess(true);
        response.setArticleId(articleDeleteRequest.getArticleId());
        return response;
    }

/*    public PageResponse<Article> queryPageArticlesByAuthorIdAndFolderId(ArticlePageQueryRequest articlePageQueryRequest) {
        Page<Article> page = new Page<>(articlePageQueryRequest.getCurrentPage(), articlePageQueryRequest.getPageSize());

        LambdaQueryWrapper<Article> queryWrapper = Wrappers.lambdaQuery(Article.class)
                .eq(Article::getFolderId, articlePageQueryRequest.getFolderId())
                .eq(Article::getAuthorId, articlePageQueryRequest.getAuthorId())
                .orderByDesc(Article::getGmtCreate);

        Page<Article> articlesPage = this.page(page, queryWrapper);

        return PageResponse.of(articlesPage.getRecords(), (int) articlesPage.getTotal(), articlePageQueryRequest.getPageSize(), articlePageQueryRequest.getCurrentPage());
    }*/

    //认为在这种场景下, 其实更多是为了folder服务的, 所以可以先写这个
    public List<Article> queryArticlesByAuthorIdAndFolderId(Long folderId, Long authorId) {
        LambdaQueryWrapper<Article> queryWrapper = Wrappers.lambdaQuery(Article.class)
                .eq(Article::getFolderId, folderId)
                .eq(Article::getAuthorId, authorId)
                .orderByDesc(Article::getGmtCreate);
        List<Article> articles = articleMapper.selectList(queryWrapper);
        return articles;
    }
}
